/************************************************
 *  @file cgi.h
 *  @brief Definition of client side of cgi iterface.
 * 
 * 	There are defined cgi_recive and cgi_responde namespaces for parse incoming and send outgoing messages.
 * 	@see draft-coar-cgi-v11-03.txt
 ************************************************/

#ifndef __cgi_h__
#define __cgi_h__

#include <cstddef>

#include "exception.h"
#include "ByteString.h"

/// Mime types.
extern char * const mime_text_plain;
/// Mime types.
extern char * const mime_text_html;
/// Mime types.
extern char * const mime_text_css;
/// Mime types.
extern char * const mime_image_ico;

/************************************************
 * Cgi_request.
 * @todo need fixed case with multiply defined meta-variables
 * @todo need undestanding in wich case need to parse incoming package
 ************************************************/
namespace cgi_request {

		/// @brief Structure for request parametres storage.
		struct RequestParam_t {
				/// Key.
				const char * key;
				/// Key size.
				size_t key_size;
				/// Value.
				const char * value;
				/// Value size.
				size_t value_size;

				/// Pointer for next structure -- there is list of parametres.
				const struct RequestParam_t * next;
		};

		/// @brief Return length of message body.
		/// @note return 0 if undefined
		size_t get_content_length() throw();

		/// @brief Return mime type of message body.
		/// @note return NULL if undefined
		const char * get_content_type() throw();

		/// @brief Return c-style string which describe CGI dialect used by server.
		const char * get_gateway_interface() throw();

		/// @brief Return c-style string with identifer of resource which script should return.
		/// @note return NULL if undefined
		const char * get_path_info() throw();

		/// @brief Return c-style string with \<query\> part of Script-URI.
		/// @note return NULL if undefined
		const char * get_query_string() throw();

		/// @brief Return c-style string with remote address.
		const char * get_remote_addr() throw();

		/// @brief Return c-style string which describe method with which request was made.
		const char * get_request_method() throw();

		/// @brief Return c-style string with URL path that could identify CGI script.
		const char * get_script_name() throw();

		/// @brief Return c-style string with name of server.
		const char * get_server_name() throw();

		/// @brief Return c-style string with port number on which request was recived.
		const char * get_server_port() throw();

		/// @brief Return c-style string with name and revision of the information protocol which the request arrived.
		const char * get_server_protocol() throw();

		/// @brief Return c-style string with name and version of the inforamtion server software.
		const char * get_server_software() throw();

		/// @brief Return pointer to message body.
		const char * get_message_body() throw();

		
		/// @brief Find request parametr with specified key.
		/// @return pointer to structure or NULL if not found
		const struct RequestParam_t * get_param(const char * _key, size_t _key_len) throw();

		/// @brief Find request parametr with key specified by c-style string.
		/// @return pointer to structure or NULL if not found
		const struct RequestParam_t * get_param_string(const char * _key) throw();

		/// List of all parametrs.
		extern const struct RequestParam_t * request_param_list;
		
		/// @brief Initialization of namespace.
		/// @param _max_content_length Set maximal length of incoming message (body).
		/// @exception std::bad_alloc returned by new
		/// @exception std::invalid_argument undefined or wrong value of one of MUST meta-variables
		/// @exception std::io_error input (stdin) error occured
		/// @exception std::length_error there is too big incoming package
		/// @exception std::logic_error there is second request for initialisation
		void construct(size_t _max_content_length = 0) throw(std::bad_alloc, std::invalid_argument, std::io_error, std::length_error, std::logic_error);

		/// @brief Shutdown namespace working.
		void destruct() throw();
}

/************************************************
 * Cgi_responde.
 ************************************************/
namespace cgi_responde {
		/// CGI status.
		extern char * const status_200_ok;
		/// CGI status.
		extern char * const status_201_created;
		/// CGI status.
		extern char * const status_202_accepted;
		
		/// CGI status.
		extern char * const status_301_moved_permanently;
		/// CGI status.
		extern char * const status_302_found;
		/// CGI status.
		extern char * const status_303_see_other;
		
		/// CGI status.
		extern char * const status_400_bad_request;
		/// CGI status.
		extern char * const status_403_forbidden;
		/// CGI status.
		extern char * const status_404_not_found;
		/// CGI status.
		extern char * const status_413_request_entity_too_large;
		/// CGI status.
		extern char * const status_415_unsupported_media_type;
		
		/// CGI status.
		extern char * const status_500_internal_server_error;
		/// CGI status.
		extern char * const status_501_not_implemented;
		/// CGI status.
		extern char * const status_503_service_unavailable;

		/// Get content type of answer.
		const char * get_content_type() throw();

		/// Setup content type of answer.
		///
		/// @exception std::bad_alloc return by new
		void set_content_type(const char * _content_type) throw( std::bad_alloc );
		
		/// Get redirection.
		const char * get_location() throw();

		/// Setup redirection.
		///
		/// @exception std::bad_alloc return by new
		void set_location(const char* _location) throw( std::bad_alloc );

		/// Get answer status.
		const char * get_status() throw();

		/// Setup answer status.
		///
		/// @exception std::bad_alloc return by new
		void set_status(const char * _status) throw( std::bad_alloc );

		/// @brief Initialization of namespace.
		///
		/// @exception std::logic_error there is second request for initialisation
		void construct() throw(std::logic_error);

		/// @brief Shutdown namespace working.
		void destruct() throw();

		/// @brief Send message.
		///
		/// @exception std::bad_alloc return by new
		/// @exception std::io_error Output error (stdout)
		/// @exception std::logic_error there is second request for send
		void send() throw(std::bad_alloc, std::io_error, std::logic_error);

		/// @brief Send extra messge (using for send error messages)
		void send_extra(const char * _status) throw();

		/// @brief Append a package content.
		///
		/// @exception std::bad_alloc return by new
		/// @exception std::out_of_range too large message (look at Package.h)
		void append(const ByteString_t & _pak) throw( std::bad_alloc, std::out_of_range );

		/// @brief Append an array of byte.
		///
		/// @exception std::bad_alloc return by new
		/// @exception std::out_of_range too large message (look at Package.h)
		void append(const char * _array, size_t _n) throw( std::bad_alloc, std::out_of_range );

		/// @brief Append a c-style string.
		///
		/// @exception std::bad_alloc return by new
		/// @exception std::out_of_range too large message (look at Package.h)
		void append(const char * _cstr) throw( std::bad_alloc, std::out_of_range );

		/// @brief Append a character.
		///
		/// @exception std::bad_alloc return by new
		/// @exception std::out_of_range too large message (look at Package.h)
		void append(const char _c) throw( std::bad_alloc, std::out_of_range );

		/// @brief Attempt to preallocate enougth memory for message.
		void reserv(size_t _size) throw( std::bad_alloc, std::out_of_range );

		/// @brief Erase message content.
		void clear() throw();
}

#endif // __cgi_h__
